use std::time::Instant;

use alice2d::{
    ecs::{
        entity,
        schedule::SystemStage,
    },
    event::{Event, WindowResizeEvent, EventDispatch},
  
    math::{Matrix4f,  Vector2f, Vector2u},
    scene::{Camera,  Scene, SceneServer},
    ui::{egui::{
        self,
        epaint::ahash::{HashMap, HashMapExt},
        vec2,  Context,  Rounding, Stroke, TextureHandle,  Ui,  FontDefinitions, style::Spacing, 
    }, self, UiOutput},
    AliceContext, Layer, render_api::ScreenDescriptorInfo, pool::Handle,
};

use crate::{
    camera::OrthographicCameraController, pipeline::editor_gui_pipeline::EditorRenderPipeline, system::physics_system, panel::{scene_panel::ScenePanel, inspect_panel::{InspectPanel, load_texture_to_egui}},
};


const PLAY_ICON: &'static str = "assets/icon/PlayButton.png";
const PAUSE_ICON: &'static str = "assets/icon/StopButton.png";

const ASPECT_RATIO:f32 = 380.0 / 640.0;


#[derive(Debug,Clone, Copy,PartialEq, Eq)]
pub enum Mode {
    Edit,
    Runtime
}

pub struct EditorLayer {
    name: &'static str,
    pub edit_scene_handle:Handle<Scene>,
    pub runtime_scene_handle:Handle<Scene>,
    ctx: AliceContext,
    editor_camera_controller: OrthographicCameraController,
    pub select_entity: Option<entity::Entity>,
    pub custom_image_texture: HashMap<String, TextureHandle>,
    pub asset_path: String,
    /// pipeline 
    /// 
    editor_pipeline:EditorRenderPipeline,
    pub platform: egui_winit_platform::Platform,
    start_time:         Instant,
    mode:Mode,
    pub window_size:Vector2u,
    pub screen_pos:Vector2f,
    pub screen_size:Vector2u,
}

impl EditorLayer {
    pub fn new(ctx: AliceContext) -> Self {

        let pipeline = EditorRenderPipeline::new(ctx.clone());
        println!("std::env::current_dir() = {:?}", std::env::current_dir());
        println!("std::env::current_exe() = {:?}", std::env::current_exe());

        let mut runtime_scene = Scene::new("runtime");

        runtime_scene.add_system_before("render", "physics", SystemStage::parallel().with_system(physics_system));

        // Scene::set_active_scene(runtime_scene);

        let server =  SceneServer::get_server_mut();
        
        let runtime_scene_handle = server.send(runtime_scene);

        let screen_size = ctx.config().get_screen_size();
        let window_size = ctx.config().get_window_size();

        let platform = egui_winit_platform::Platform::new(egui_winit_platform::PlatformDescriptor {
            physical_width:     window_size.x,
            physical_height:    window_size.y,
            scale_factor:       1.0,
            font_definitions:   FontDefinitions::default(),
            style:              Default::default(),
        });

        let gui_ctx = platform.context();

        let mut visuals = egui::Visuals::dark();

        visuals.window_rounding = Rounding::none();

        visuals.widgets.inactive.bg_stroke = Stroke::none();
        visuals.widgets.hovered.bg_stroke = Stroke::none();
        visuals.widgets.active.bg_stroke = Stroke::none();
    
        visuals.widgets.inactive.rounding = Rounding::none();
        visuals.widgets.hovered.rounding = Rounding::none();
        visuals.widgets.active.rounding = Rounding::none();

        // button_padding

        let mut spacing = Spacing::default();
        spacing.button_padding = vec2(7.0, 5.0);

        spacing.item_spacing = vec2(0.0, 4.0);
        // spacing.interact_size = vec2(100.0, 20.0);
        spacing.slider_width = 200.0;

        spacing.icon_width = 12.0;
        spacing.icon_width_inner = 10.0;
   

        let mut style = (*gui_ctx.style()).clone();
        style.spacing = spacing;
    

        gui_ctx.set_style(style);

        gui_ctx.set_visuals(visuals);

     

        let edit_scene_handle = server.send(Scene::new("editor"));

        // 默认编辑场景为激活的场景
        server.set_active_scene(edit_scene_handle);
        Self {
            name: "editor_layer",
            edit_scene_handle,
            runtime_scene_handle,
            ctx,
            editor_camera_controller: OrthographicCameraController::new(window_size.x as f32 / window_size.y as f32, Some(true)),
            editor_pipeline:pipeline,
            select_entity: None,
            custom_image_texture: HashMap::new(),
            asset_path: String::from("assets"),
            mode:Mode::Edit,
            start_time:Instant::now(),
            platform,
            screen_pos:Default::default(),
            screen_size,
            window_size
        }
    }

    

    pub fn play(&mut self) {
        let server = SceneServer::get_server_mut();
        let edit_scene = server.get_active();
        if edit_scene.check_primary_camera() {

            server.set_active_scene(self.runtime_scene_handle);

            let (edit_scene,runtime_scene) = server.get_scene_two_mut(self.edit_scene_handle,self.runtime_scene_handle);
            runtime_scene.copy_from(edit_scene);
            
            runtime_scene.prepare_scene(self.ctx.clone());
          
        
       
            self.mode = Mode::Runtime;
        }else {
            println!("场景未设置主相机");
        }

      
    }

    pub fn pause(&mut self){
        let server = SceneServer::get_server_mut();
        server.set_active_scene(self.edit_scene_handle);

        self.mode = Mode::Edit;
    }


}

impl Layer for EditorLayer {
    fn attach(&mut self) {

        let server = SceneServer::get_server_mut();
        let edit_scene = server.get_scene_mut(self.edit_scene_handle);
        edit_scene
            .world
            .insert_non_send_resource(self.ctx.clone());
        // This system moves each entity with a Position and Velocity component

        let runtime_scene = server.get_scene_mut(self.runtime_scene_handle);
     
        runtime_scene
        .world
        .insert_non_send_resource(self.ctx.clone());
    }

    fn begin_frame(&mut self) {
        self.platform.update_time(self.start_time.elapsed().as_secs_f64());
        self.platform.begin_frame();
    }

    fn update(&mut self, dt: f64) {
        // println!("{} layer is update! dt = {}", self.get_name(),dt);
        // scene.tick();
        self.render_editor();
        let server = SceneServer::get_server_mut();
        let runtime_scene = server.get_active_scene_mut();
        match self.mode {
            Mode::Edit =>{ 
                self.editor_camera_controller.tick(dt);
                let camera = Matrix4f::webgl_to_wgpu(
                    self.editor_camera_controller
                        .get_camera()
                        .get_view_projection(),
                );
                runtime_scene.update_world_transform();
                
                self.ctx.update_scene_data(camera);

                runtime_scene.tick(dt);
               
            }
            Mode::Runtime => {
            
                // self.runtime_scene.update_world_transform();
                // let camera = self.runtime_scene.get_camera_view();

                self.editor_camera_controller.tick(dt);
                let camera = Matrix4f::webgl_to_wgpu(
                    self.editor_camera_controller
                        .get_camera()
                        .get_view_projection(),
                );
                self.ctx.update_scene_data(camera);
              
                runtime_scene.pre_tick(dt, self.ctx.clone());
                runtime_scene.tick(dt);
            }
        }
    }

    fn ui_render(&mut self, _ctx: &mut Context) {
        // println!("{} layer is render_ui !", self.get_name());

        // self.demo_app.ui(ctx);

    }

    fn detach(&mut self) {
        println!("{} layer is detach !", self.get_name());
    }

    fn event(&mut self, event: &mut Box<dyn Event>) {
        self.editor_camera_controller.event(event);
        let mut event_dispatch = EventDispatch::new(event);
        event_dispatch.dispatch::<WindowResizeEvent, _>(|e| {
            self.window_resize(e)
        });
    }

    fn get_name(&self) -> &'static str {
        self.name
    }

    fn end_frame(&mut self) {
        let size = self.ctx.config().get_window_size();
     
        let screen_descriptor = ScreenDescriptorInfo {
            view_port_size:size,
            scale_factor: 1.0,
        };
       
        let full_output = self.platform.end_frame(None);
        let paint_jobs = self.platform.context().tessellate(full_output.shapes);

        self.editor_pipeline.draw(UiOutput {
            texture_delta:full_output.textures_delta ,
            primitive:paint_jobs
        }, &screen_descriptor)
    }

    fn as_any(&self) -> &dyn std::any::Any {
        self as &dyn std::any::Any
    }

    fn as_any_mut(&mut self) -> &mut dyn std::any::Any {
        self as  &mut dyn std::any::Any
    }
}

impl EditorLayer {

    fn render_editor(&mut self){
        let mut ctx = self.platform.context();
        self.render_menu_bar(&mut ctx);

        ScenePanel::draw_scene_tree(&mut ctx, self);
        InspectPanel::draw_inspector(self,&mut ctx);

        // AssetPanel::draw_assets(layer, &mut ctx);
        self.render_viewport(&mut ctx);
    }


   
    pub fn render_viewport(&mut self, ctx: &mut Context) {
        //  let  screen_id =
        
        alice2d::ui::egui::CentralPanel::default().show(ctx, |ui| {
            self.render_tool_bar(ui);
            let pos = ui.next_widget_position();

            let width = ui.available_width();
            let height = width * ASPECT_RATIO;
            let size = Vector2u::new(width as u32 , height as u32);
            let pos = Vector2f::new(pos.x,pos.y);
            if self.screen_pos != pos || self.screen_size != size {
                self.screen_pos = pos;
                self.screen_size = size;
                self.ctx.update_screen_info(pos, size);
            }
   
        
            ui.image(self.editor_pipeline.output_id, vec2(width, height));

            // self.render_assets(ui);
        });
    }

    pub fn render_menu_bar(&mut self, ctx: &mut Context) {
        alice2d::ui::egui::TopBottomPanel::top("menu_tool").show(ctx, |ui|{
            ui.menu_button("file", |ui|{
                Self::file_menus(ui,self);
            });
        });
    }

    pub fn render_tool_bar(&mut self, ui: &mut Ui) {
        ui.horizontal(|ui| {
            if !self.custom_image_texture.contains_key(PLAY_ICON) {
                              
                if let Some(handle) = load_texture_to_egui(ui,PLAY_ICON) {
                    self.custom_image_texture
                    .insert(PLAY_ICON.to_owned(), handle);
                }
            }
            if let Some(handle) = self.custom_image_texture.get(&PLAY_ICON.to_owned()) {
                if ui.add( alice2d::ui::egui::ImageButton::new(handle, vec2(16.0_f32, 16.0_f32))).clicked() {
                   self.play()
                }
            }
            if !self.custom_image_texture.contains_key(PAUSE_ICON) {
                              
                if let Some(handle) = load_texture_to_egui(ui,PAUSE_ICON) {
                    self.custom_image_texture
                    .insert(PAUSE_ICON.to_owned(), handle);
                }
            }
            if let Some(handle) = self.custom_image_texture.get(&PAUSE_ICON.to_owned()) {
                if ui.add( alice2d::ui::egui::ImageButton::new(handle, vec2(16.0_f32, 16.0_f32))).clicked() {
                    self.pause()
                }
            }

       
            // let camera = &mut self.camera_controller.camera.borrow_mut();
            //   let mut is_orthographic = camera.camera_type == CameraType::Orthographic;
            //   if  ui.checkbox(&mut is_orthographic, "2D").changed() {
            //       if is_orthographic {
            //           camera.set_camera_type(CameraType::Orthographic);
            //       } else {
            //             camera.set_camera_type(CameraType::Perspective);
            //       }
            //   }
        });
    }

   
}




/// menu
impl EditorLayer {
    fn file_menus(ui: &mut egui::Ui,layer:&mut EditorLayer) {
        let server = SceneServer::get_server();
        let edit_scene = server.get_scene(layer.edit_scene_handle);
        if ui.button("Save Scene").clicked() {
            edit_scene.serialize();
            ui.close_menu();
        }
        ui.menu_button("SubMenu", |ui| {
            ui.menu_button("SubMenu", |ui| {
                if ui.button("Open...").clicked() {
                    ui.close_menu();
                }
                let _ = ui.button("Item");
            });
            ui.menu_button("SubMenu", |ui| {
                if ui.button("Open...").clicked() {
                    ui.close_menu();
                }
                let _ = ui.button("Item");
            });
            let _ = ui.button("Item");
            if ui.button("Open...").clicked() {
                ui.close_menu();
            }
        });
        ui.menu_button("SubMenu", |ui| {
            let _ = ui.button("Item1");
            let _ = ui.button("Item2");
            let _ = ui.button("Item3");
            let _ = ui.button("Item4");
            if ui.button("Open...").clicked() {
                ui.close_menu();
            }
        });
        let _ = ui.button("Very long text for this item");
    }
}

/// viewport
impl EditorLayer {
    pub fn window_resize(&mut self , event:&mut WindowResizeEvent) -> bool {

        // self.editor_pipeline.resize(self.ctx.clone(),event.get_window_size());
  

        return false;
    }
}   
